<template>
    <div class="workflow-editor">
        <div class="editor-toolbar">
            <div class="editor-actions">
                <button @click="exportJSON" class="action-button">
                    <span class="icon">📤</span> 导出JSON
                </button>
                <button @click="importJSON" class="action-button">
                    <span class="icon">📥</span> 导入JSON
                </button>
                <button @click="clearEditor" class="action-button clear">
                    <span class="icon">🗑️</span> 清空编辑器
                </button>
            </div>
        </div>

        <div class="editor-layout">
            <!-- 左侧可拖动组件栏 -->
            <div class="component-sidebar" :class="{ 'sidebar-collapsed': sidebarCollapsed }">
                <div class="sidebar-toggle" @click="toggleSidebar">
                    {{ sidebarCollapsed ? '›' : '‹' }}
                </div>

                <h3 class="sidebar-title">组件库</h3>

                <div class="component-list">
                    <component
                            v-for="type in nodeTypes"
                            :key="type.id"
                            :is="type.component"
                            :data="type"
                            class="component-item"
                            :style="{ borderColor: type.color }"
                            draggable="true"
                            @dragstart="onDragStart($event, type.id)"
                    />
                </div>
            </div>

            <!-- 右侧编辑区域 -->
            <div
                    class="editor-container"
                    ref="container"
                    @dragover="onDragOver"
                    @drop="onDrop"
                    @dragenter="onDragEnter"
                    @dragleave="onDragLeave"
                    :class="{ 'drag-over': isDraggingOver }"
            ></div>

            <div v-if="showJsonPreview" class="json-preview">
                <div class="json-preview-header">
                    <h3>JSON预览</h3>
                    <button @click="showJsonPreview = false" class="close-button">×</button>
                </div>
                <pre class="json-content">{{ JSON.stringify(jsonData, null, 2) }}</pre>
            </div>

            <div v-if="showJsonImport" class="json-import">
                <div class="json-import-header">
                    <h3>导入JSON</h3>
                    <button @click="showJsonImport = false" class="close-button">×</button>
                </div>
                <textarea v-model="importJsonText" placeholder="粘贴JSON数据到这里..."></textarea>
                <div class="import-actions">
                    <button @click="loadWorkflowFromText()" class="import-button">导入</button>
                    <button @click="showJsonImport = false" class="cancel-button">取消</button>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
import { ref, onMounted, onBeforeUnmount, reactive } from 'vue';
import { nodeTypes } from './components/index.js';
import { StartNode, ProcessNode, ConditionNode, EndNode } from './components/index.js';

// 这里需要安装以下依赖:
// npm install rete rete-area-plugin rete-connection-plugin rete-vue-plugin
export default {
    name: 'WorkflowEditor',
    components: {
        StartNode,
        ProcessNode,
        ConditionNode,
        EndNode
    },
    setup() {
        const container = ref(null);
        const editor = ref(null);
        const showJsonPreview = ref(false);
        const showJsonImport = ref(false);
        const importJsonText = ref('');
        const jsonData = ref({});
        const sidebarCollapsed = ref(false);

        // 拖拽相关状态
        const draggedNodeType = ref(null);
        const isDraggingOver = ref(false);

        // 在实际项目中，需要导入这些模块
        // 这里仅作为示例，实际使用时需要安装相应的依赖
        let Rete, AreaPlugin, ConnectionPlugin, VuePlugin;

        // 初始化编辑器
        const initEditor = async () => {
            try {
                // 在实际项目中，这些模块应该通过import导入
                // 这里模拟动态导入
                const modules = await Promise.all([
                    import('rete'),
                    import('rete-area-plugin'),
                    import('rete-connection-plugin'),
                    import('rete-vue-plugin')
                ]);

                Rete = modules[0].default;
                AreaPlugin = modules[1].AreaPlugin;
                ConnectionPlugin = modules[2].ConnectionPlugin;
                VuePlugin = modules[3].VuePlugin;

                // 创建编辑器实例
                editor.value = new Rete.NodeEditor('workflow@1.0.0', container.value);

                // 使用插件
                editor.value.use(ConnectionPlugin);
                editor.value.use(VuePlugin);
                editor.value.use(AreaPlugin, { background: true, snap: true });

                // 注册组件
                registerComponents();

                // 监听变化
                editor.value.on('process nodecreated noderemoved connectioncreated connectionremoved', () => {
                    updateJSON();
                });

                // 初始化完成
                editor.value.view.resize();
                editor.value.trigger('process');
            } catch (error) {
                console.error('初始化编辑器失败:', error);
            }
        };

        // 注册节点组件
        const registerComponents = () => {
            if (!editor.value) return;

            // 创建Socket
            const socket = new Rete.Socket('Default');

            // 为每种节点类型创建组件
            nodeTypes.forEach(type => {
                const component = new Rete.Component(type.label);

                // 设置构建器
                component.builder = node => {
                    node.data.type = type.id;
                    node.data.color = type.color;

                    // 添加输入
                    for (let i = 0; i < type.inputs; i++) {
                        const input = new Rete.Input(`input-${i}`, `输入 ${i+1}`, socket, true);
                        node.addInput(input);
                    }

                    // 添加输出
                    for (let i = 0; i < type.outputs; i++) {
                        const output = new Rete.Output(`output-${i}`, `输出 ${i+1}`, socket, true);
                        node.addOutput(output);
                    }

                    // 添加控件
                    if (type.id === 'process' || type.id === 'condition') {
                        const ctrl = new Rete.Control('text', {
                            component: {
                                data() {
                                    return { value: node.data.value || '' };
                                },
                                template: `<input type="text" v-model="value" @input="update" placeholder="输入值"/>`,
                                methods: {
                                    update() {
                                        node.data.value = this.value;
                                        editor.value.trigger('process');
                                    }
                                }
                            },
                            props: { emitter: editor.value }
                        });
                        node.addControl(ctrl);
                    }

                    return node;
                };

                // 设置worker
                component.worker = (node, inputs, outputs) => {
                    // 处理节点逻辑
                    const inputData = inputs['input-0'] ? inputs['input-0'][0] : null;

                    if (type.id === 'start') {
                        outputs['output-0'] = { value: 'start' };
                    } else if (type.id === 'process') {
                        outputs['output-0'] = { value: node.data.value || inputData?.value || '' };
                    } else if (type.id === 'condition') {
                        // 条件节点有两个输出
                        outputs['output-0'] = { value: 'true', condition: true };
                        outputs['output-1'] = { value: 'false', condition: false };
                    }
                    // end节点不需要输出
                };

                // 注册组件
                editor.value.register(component);
            });
        };

        // 更新JSON数据
        const updateJSON = async () => {
            if (!editor.value) return;

            try {
                // 获取编辑器数据
                const data = editor.value.toJSON();

                // 转换为工作流格式
                const workflow = {
                    nodes: Object.values(data.nodes).map(node => ({
                        id: node.id,
                        type: node.data.type,
                        position: node.position,
                        value: node.data.value || ''
                    })),
                    connections: data.connections.map(conn => ({
                        source: conn.source,
                        sourceOutput: conn.sourceOutput,
                        target: conn.target,
                        targetInput: conn.targetInput
                    }))
                };

                jsonData.value = workflow;
            } catch (error) {
                console.error('更新JSON失败:', error);
            }
        };

        // 导出JSON
        const exportJSON = () => {
            showJsonPreview.value = !showJsonPreview.value;
            updateJSON();
        };

        // 获取节点图标
        const getNodeIcon = (type) => {
            switch (type) {
                case 'start': return '▶';
                case 'process': return '⚙';
                case 'condition': return '?';
                case 'end': return '■';
                default: return '#';
            }
        };

        // 导入JSON
        const importJSON = () => {
            // 显示导入对话框
            showJsonImport.value = true;
        };

        // 从文本导入工作流
        const loadWorkflowFromText = () => {
            if (!importJsonText.value) return;

            try {
                const data = JSON.parse(importJsonText.value);
                loadWorkflow(data);
                showJsonImport.value = false;
                importJsonText.value = '';
            } catch (error) {
                console.error('导入JSON失败:', error);
                alert('JSON格式错误，请检查后重试');
            }
        };

        // 从文件导入工作流
        const importJSONFromFile = () => {
            const input = document.createElement('input');
            input.type = 'file';
            input.accept = '.json';
            input.onchange = e => {
                const file = e.target.files[0];
                if (!file) return;

                const reader = new FileReader();
                reader.onload = event => {
                    try {
                        const data = JSON.parse(event.target.result);
                        loadWorkflow(data);
                    } catch (error) {
                        console.error('导入JSON失败:', error);
                        alert('JSON格式错误，请检查后重试');
                    }
                };
                reader.readAsText(file);
            };
            input.click();
        };

        // 加载工作流
        const loadWorkflow = async (data) => {
            if (!editor.value || !data.nodes) return;

            // 清空编辑器
            await clearEditor();

            // 创建节点
            for (const nodeData of data.nodes) {
                const type = nodeTypes.find(t => t.id === nodeData.type);
                if (!type) continue;

                const component = editor.value.components.get(type.label);
                if (!component) continue;

                const node = await component.createNode();
                node.position = nodeData.position;
                node.data.value = nodeData.value;
                node.data.type = nodeData.type;
                node.data.color = type.color;

                editor.value.addNode(node);
            }

            // 创建连接
            if (data.connections) {
                for (const conn of data.connections) {
                    const sourceNode = editor.value.nodes.find(n => n.id === conn.source);
                    const targetNode = editor.value.nodes.find(n => n.id === conn.target);

                    if (sourceNode && targetNode) {
                        const output = sourceNode.outputs.get(conn.sourceOutput);
                        const input = targetNode.inputs.get(conn.targetInput);

                        if (output && input) {
                            editor.value.connect(output, input);
                        }
                    }
                }
            }

            editor.value.view.resize();
            editor.value.trigger('process');
            updateJSON();
        };

        // 清空编辑器
        const clearEditor = async () => {
            if (!editor.value) return;

            // 删除所有节点
            editor.value.nodes.forEach(node => {
                editor.value.removeNode(node);
            });

            editor.value.view.resize();
            editor.value.trigger('process');
            updateJSON();
        };

        // 添加节点的方法
        const addNode = async (type, x, y) => {
            if (!editor.value) return;

            const typeConfig = nodeTypes.find(t => t.id === type);
            if (!typeConfig) return;

            const component = editor.value.components.get(typeConfig.label);
            if (!component) return;

            const node = await component.createNode();
            node.position = [x, y];

            editor.value.addNode(node);
            editor.value.view.resize();
            editor.value.trigger('process');
        };

        // 拖拽开始事件处理
        const onDragStart = (event, nodeType) => {
            draggedNodeType.value = nodeType;
            // 设置拖拽图像和效果
            const typeConfig = nodeTypes.find(t => t.id === nodeType);
            if (typeConfig) {
                event.dataTransfer.setData('text/plain', nodeType);
                event.dataTransfer.effectAllowed = 'copy';

                // 创建自定义拖拽图像
                const dragImage = event.target.cloneNode(true);
                dragImage.style.opacity = '0.7';
                dragImage.style.position = 'absolute';
                dragImage.style.top = '-1000px';
                document.body.appendChild(dragImage);
                event.dataTransfer.setDragImage(dragImage, 20, 20);

                // 延迟移除拖拽图像
                setTimeout(() => {
                    document.body.removeChild(dragImage);
                }, 0);
            }
        };

        // 拖拽进入事件处理
        const onDragEnter = (event) => {
            event.preventDefault();
            isDraggingOver.value = true;
        };

        // 拖拽离开事件处理
        const onDragLeave = (event) => {
            // 确保只有当鼠标离开编辑区域时才重置状态
            if (!event.currentTarget.contains(event.relatedTarget)) {
                isDraggingOver.value = false;
            }
        };

        // 拖拽经过事件处理
        const onDragOver = (event) => {
            // 阻止默认行为以允许放置
            event.preventDefault();
            event.dataTransfer.dropEffect = 'copy';
        };

        // 放置事件处理
        const onDrop = async (event) => {
            event.preventDefault();
            isDraggingOver.value = false;

            // 获取拖拽的节点类型
            const nodeType = event.dataTransfer.getData('text/plain') || draggedNodeType.value;
            if (!nodeType) return;

            // 获取放置位置（相对于编辑器容器）
            const rect = container.value.getBoundingClientRect();
            const x = event.clientX - rect.left;
            const y = event.clientY - rect.top;

            // 确保坐标在编辑器容器内
            const safeX = Math.max(0, Math.min(x, rect.width));
            const safeY = Math.max(0, Math.min(y, rect.height));

            // 添加节点到放置位置
            await addNode(nodeType, safeX, safeY);

            // 重置拖拽状态
            draggedNodeType.value = null;
        };

        // 切换侧边栏折叠状态
        const toggleSidebar = () => {
            sidebarCollapsed.value = !sidebarCollapsed.value;
        };

        // 生命周期钩子
        onMounted(() => {
            initEditor();
        });

        onBeforeUnmount(() => {
            if (editor.value) {
                editor.value.destroy();
            }
        });

        return {
            container,
            nodeTypes,
            showJsonPreview,
            showJsonImport,
            importJsonText,
            jsonData,
            sidebarCollapsed,
            exportJSON,
            importJSON,
            importJSONFromFile,
            loadWorkflowFromText,
            clearEditor,
            addNode,
            getNodeIcon,
            onDragStart,
            onDragEnter,
            onDragLeave,
            onDragOver,
            onDrop,
            toggleSidebar,
            isDraggingOver
        };
    }
};
</script>

<style scoped>
.workflow-editor {
    display: flex;
    flex-direction: column;
    height: 100%;
    width: 100%;
    background-color: #f5f5f5;
    position: relative;
}

.editor-layout {
    display: flex;
    flex: 1;
    overflow: hidden;
    position: relative;
}

.editor-toolbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px 20px;
    background-color: #fff;
    border-bottom: 1px solid #e0e0e0;
    z-index: 10;
}

.editor-actions {
    display: flex;
    gap: 10px;
}

.action-button {
    display: flex;
    align-items: center;
    padding: 8px 16px;
    border: none;
    border-radius: 4px;
    background-color: #2196F3;
    color: white;
    cursor: pointer;
    font-size: 14px;
    transition: background-color 0.3s;
}

.action-button:hover {
    background-color: #0b7dda;
}

.action-button.clear {
    background-color: #F44336;
}

.action-button.clear:hover {
    background-color: #d32f2f;
}

.icon {
    margin-right: 6px;
    font-size: 16px;
}

.component-sidebar {
    width: 220px;
    background-color: #fff;
    border-right: 1px solid #e0e0e0;
    display: flex;
    flex-direction: column;
    transition: width 0.3s ease;
    position: relative;
    z-index: 5;
    overflow-y: auto;
    overflow-x: hidden;
}

.sidebar-collapsed {
    width: 50px;
}

.sidebar-toggle {
    position: absolute;
    top: 10px;
    right: 10px;
    width: 24px;
    height: 24px;
    background-color: #f0f0f0;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    font-size: 18px;
    z-index: 10;
    transition: background-color 0.2s;
}

.sidebar-toggle:hover {
    background-color: #e0e0e0;
}

.sidebar-title {
    padding: 15px 15px 10px;
    margin: 0;
    font-size: 16px;
    color: #333;
    border-bottom: 1px solid #eee;
}

.sidebar-collapsed .sidebar-title {
    text-align: center;
    font-size: 0;
    padding: 15px 0;
}

.component-list {
    padding: 15px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.sidebar-collapsed .component-list {
    padding: 15px 5px;
    align-items: center;
}

.component-item {
    display: flex;
    align-items: center;
    padding: 8px 10px;
    border-radius: 6px;
    background-color: #f9f9f9;
    cursor: grab;
    transition: all 0.2s;
    user-select: none;
}

.component-item:hover {
    background-color: #f0f0f0;
    transform: translateY(-2px);
    box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}

.component-item:active {
    cursor: grabbing;
}

.sidebar-collapsed .component-item {
    flex-direction: column;
    padding: 8px 0;
}

.component-icon {
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 4px;
    color: white;
    font-size: 16px;
    margin-right: 10px;
    flex-shrink: 0;
}

.sidebar-collapsed .component-icon {
    margin-right: 0;
    margin-bottom: 4px;
}

.component-label {
    font-size: 14px;
    color: #555;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sidebar-collapsed .component-label {
    font-size: 0;
    display: none;
}

.editor-container {
    flex: 1;
    overflow: hidden;
    position: relative;
    min-height: 500px;
    background-color: #f8f8f8;
    background-image: radial-gradient(#e0e0e0 1px, transparent 1px);
    background-size: 20px 20px;
    transition: all 0.3s ease;
}

.editor-area.drag-over {
    background-color: rgba(33, 150, 243, 0.1);
    box-shadow: inset 0 0 0 2px #2196F3;
}

.json-preview,
.json-import {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 80%;
    max-width: 600px;
    max-height: 80vh;
    background-color: white;
    border-radius: 8px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
    z-index: 100;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.json-preview-header,
.json-import-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 12px 16px;
    background-color: #f5f5f5;
    border-bottom: 1px solid #e0e0e0;
}

.json-preview-header h3,
.json-import-header h3 {
    margin: 0;
    font-size: 18px;
    color: #333;
}

.close-button {
    background: none;
    border: none;
    font-size: 24px;
    cursor: pointer;
    color: #666;
}

.json-content {
    padding: 16px;
    overflow: auto;
    max-height: 60vh;
    font-family: monospace;
    white-space: pre-wrap;
    background-color: #f8f8f8;
    border-radius: 4px;
    margin: 16px;
}

.json-import textarea {
    margin: 16px;
    padding: 12px;
    height: 200px;
    border: 1px solid #ddd;
    border-radius: 4px;
    font-family: monospace;
    resize: none;
}

.import-actions {
    display: flex;
    justify-content: flex-end;
    padding: 0 16px 16px;
    gap: 12px;
}

.import-button,
.cancel-button {
    padding: 8px 16px;
    border-radius: 4px;
    font-size: 14px;
    cursor: pointer;
}

.import-button {
    background-color: #1976d2;
    color: white;
    border: none;
}

.cancel-button {
    background-color: #f5f5f5;
    border: 1px solid #ddd;
    color: #333;
}

/* Rete.js 自定义样式 */
:deep(.node) {
    border-radius: 8px;
    box-shadow: 0 2px 5px rgba(0,0,0,0.15);
    min-width: 180px;
}

:deep(.node .title) {
    border-radius: 8px 8px 0 0;
    padding: 10px;
    font-weight: bold;
}

:deep(.node .output) {
    margin: 6px;
}

:deep(.node .input) {
    margin: 6px;
}

:deep(.node .control) {
    padding: 6px 18px;
}

:deep(.node .control input) {
    width: 100%;
    border: 1px solid #ddd;
    border-radius: 4px;
    padding: 6px;
    font-size: 14px;
}
</style>
